package com.qingyun.cameralab.preview_capture

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Rect
import android.graphics.RectF
import android.view.View
import androidx.annotation.ColorInt
import androidx.camera.view.PreviewView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
import java.io.FileOutputStream

class PreviewCaptureHelper private constructor(builder: Builder) {
    private val context: Context = builder.context
    private val rootView: View
    private val previewView: PreviewView?
    private val outputFormat: Bitmap.CompressFormat
    private val outputQuality: Int
    private val backgroundColor: Int
    private val callback: CaptureCallback

    init {
        rootView = builder.rootView
        previewView = builder.previewView
        outputFormat = builder.outputFormat
        outputQuality = builder.outputQuality
        backgroundColor = builder.backgroundColor
        callback = builder.callback
    }

    fun capture() {
        CoroutineScope(Dispatchers.Main).launch {
            callback.onCaptureStart()
            try {
                val result = performCapture()
                callback.onCaptureSuccess(result)
            } catch (e: Exception) {
                callback.onCaptureError(e)
            }

        }
    }

    private fun performCapture(): CaptureResult {
        //获取预览画面
        val previewBitmap = previewView?.bitmap?.copy(
            Bitmap.Config.ARGB_8888,
            true
        )
        //完整的截图(不包含预览部分)
        val baseBitmap = getBaseScreenShot()
        val finalBitmap = if (previewBitmap != null && previewView != null) {
            combineBitmap(baseBitmap, previewBitmap, previewView)
        } else {
            baseBitmap
        }
        //保存文件
        val outputFile = saveToFile(finalBitmap)
        recycleBitmap(baseBitmap, previewBitmap)
        return CaptureResult(finalBitmap, outputFile)
    }

    private fun saveToFile(bitmap: Bitmap): File? {
        return try {
            val file = File(context.cacheDir, "capture_${System.currentTimeMillis()}.jpg")
            FileOutputStream(file).use {
                bitmap.compress(outputFormat, outputQuality, it)
            }
            file
        } catch (e: Exception) {
            null
        }
    }

    private fun recycleBitmap(vararg bitmaps: Bitmap?) {
        bitmaps.forEach {
            it?.apply {
                if (!it.isRecycled) {
                    recycle()
                }
            }
        }
    }

    private fun combineBitmap(
        baseBitmap: Bitmap,
        previewBitmap: Bitmap,
        previewView: PreviewView,
    ): Bitmap {

        return Bitmap.createBitmap(
            baseBitmap.width,
            baseBitmap.height,
            baseBitmap.config!!
        ).also {
            val canvas = Canvas(it).apply {
                drawColor(backgroundColor)
            }
            canvas.drawBitmap(baseBitmap, 0f, 0f, null)

            //计算预览区域在屏幕上的位置
            val viewRect = RectF(
                previewView.left.toFloat(),
                previewView.top.toFloat(),
                previewView.right.toFloat(),
                previewView.bottom.toFloat()
            )
            canvas.drawBitmap(
                previewBitmap,
                Rect(0, 0, previewBitmap.width, previewBitmap.height),
                viewRect,
                null
            )
        }
    }

    private fun getBaseScreenShot(): Bitmap {
        //创建临时禁用视图
        previewView?.isEnabled = false
        val bitmap = Bitmap.createBitmap(
            rootView.width,
            rootView.height,
            Bitmap.Config.ARGB_8888
        )
        val canvas = Canvas(bitmap)
        rootView.draw(canvas)
        //恢复视图
        previewView?.isEnabled = true
        return bitmap
    }

    class Builder(val context: Context) {
        lateinit var rootView: View
        var previewView: PreviewView? = null
        var outputFormat: Bitmap.CompressFormat = Bitmap.CompressFormat.JPEG
        var outputQuality: Int = 85
        var backgroundColor: Int = Color.TRANSPARENT
        lateinit var callback: CaptureCallback
        fun setRootView(rootView: View): Builder {
            this.rootView = rootView
            return this
        }

        fun setPreviewView(previewView: PreviewView): Builder {
            this.previewView = previewView
            return this
        }

        fun setOutputFormat(outputFormat: Bitmap.CompressFormat): Builder {
            this.outputFormat = outputFormat
            return this
        }

        fun setOutputQuality(outputQuality: Int): Builder {
            this.outputQuality = outputQuality
            return this
        }

        fun setCaptureCallback(callback: CaptureCallback): Builder {
            this.callback = callback
            return this
        }

        fun setBackgroundColor(@ColorInt backgroundColor: Int): Builder {
            this.backgroundColor = backgroundColor
            return this
        }

        fun build(): PreviewCaptureHelper {
            require(::rootView.isInitialized) { "rootView must be set" }
            require(::callback.isInitialized) { "callback must be set" }
            return PreviewCaptureHelper(this)
        }
    }

    interface CaptureCallback {
        fun onCaptureStart()
        fun onCaptureSuccess(result: CaptureResult)
        fun onCaptureError(e: Exception)
    }

    data class CaptureResult(
        val bitmap: Bitmap?,
        val file: File?,
    )
}